using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace AntEater.ComponentModel
{
    /// <summary>
    /// Provides a mechanism to rack the changing of a property.
    /// </summary>
    internal class PropertyChangeTracker
    {

        /// <summary>
        /// Occurs when a tracked property has changed.
        /// </summary>
        public event EventHandler<TrackedPropertyChangedEventArgs> TrackedPropertyChanged; 

        /// <summary>
        /// Initializes a new instance of the <see cref="T:PropertyChangeTracker"/> class.
        /// </summary>
        /// <param name="trackedPropertyName">Name of the tracked property.</param>
        public PropertyChangeTracker(string trackedPropertyName) {
            this._trackedPropertyName = trackedPropertyName;
            this._trackedObjects = new TrackedObjectsCollection();
        }

        private string _trackedPropertyName;

        /// <summary>
        /// Gets or sets the name of the tracked property.
        /// </summary>
        /// <value>The name of the tracked property.</value>
        public string TrackedPropertyName {
            get { return _trackedPropertyName; }
        }

        private TrackedObjectsCollection _trackedObjects;

        /// <summary>
        /// Gets or sets the tracked objects.
        /// </summary>
        /// <value>The tracked objects.</value>
        private TrackedObjectsCollection TrackedObjects {
            get { return _trackedObjects; }
        }

        /// <summary>
        /// Registers an object for tracking.
        /// </summary>
        /// <param name="objectToRegister">The object to register.</param>
        public void RegisterObject(INotifyPropertyChanged objectToRegister) {
            if (!this.TrackedObjects.Contains(objectToRegister)) {

                TrackingData trackingData = new TrackingData(objectToRegister, this.TrackedPropertyName);

                trackingData.TrackedPropertyChanged += new EventHandler<TrackedPropertyChangedEventArgs>(TrackingDataTrackedPropertyChanged);

                this.TrackedObjects.Add(trackingData);
            }
        }

        /// <summary>
        /// UnRegisters an object for tracking.
        /// </summary>
        /// <param name="objectToUnregister">The object to unregister.</param>
        public void UnregisterObject(INotifyPropertyChanged objectToUnregister) {
            if (this.TrackedObjects.Contains(objectToUnregister)) {

                TrackingData trackingData = this.TrackedObjects[objectToUnregister];

                trackingData.TrackedPropertyChanged -= new EventHandler<TrackedPropertyChangedEventArgs>(TrackingDataTrackedPropertyChanged);

                this.TrackedObjects.Remove(objectToUnregister);
            }
        }

        /// <summary>
        /// Called when [tracked property changed].
        /// </summary>
        /// <param name="trackedItem">The tracked item.</param>
        /// <param name="oldPropertyValue">The old property value.</param>
        /// <param name="newPropertyValue">The new property value.</param>
        protected void OnTrackedPropertyChanged(object trackedItem, object oldPropertyValue, object newPropertyValue) {
            if (this.TrackedPropertyChanged != null) {
                this.TrackedPropertyChanged(this, new TrackedPropertyChangedEventArgs(trackedItem, oldPropertyValue, newPropertyValue));
            }
        }

        /// <summary>
        /// Trackings the data tracked property changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="T:AntEater.ComponentModel.TrackedPropertyChangedEventArgs"/> instance containing the event data.</param>
        private void TrackingDataTrackedPropertyChanged(object sender, TrackedPropertyChangedEventArgs e) {
            this.OnTrackedPropertyChanged(e.TrackedItem, e.OldPropertyValue, e.NewPropertyValue);
        }
    }
}
